package com.atldy.commerce.controller;

import com.alibaba.fastjson.JSON;
import com.atldy.commerce.service.CacheHystrixAnnotationsCommond;
import com.atldy.commerce.service.CacheHystrixServiceCommand;
import com.atldy.commerce.service.HystrixService;
import com.atldy.commerce.service.HystrixServiceCommand;
import com.atldy.commerce.service.NacosClientHystrixObservableCommand;
import com.atldy.commerce.service.NacosClientService;
import com.atldy.commerce.service.request_merge.NacosClientCollapseCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import rx.Observable;
import rx.Observer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @version 1.0
 * @Author: li-dong-yang
 * @CreateTime: 2021-09-07 7:09
 * @Description 熔断降级测试
 */
@Slf4j
@RestController
@RequestMapping("/hystrix")
public class HystrixController {

    @Autowired
    private HystrixService hystrixService;

    @Autowired
    private NacosClientService nacosClientService;

    @Autowired
    private CacheHystrixAnnotationsCommond cacheHystrixAnnotationsCommond;

    @GetMapping("/getServiceInstance-hystrix")
    public List<ServiceInstance> getServiceInstance(@RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        log.info("服务名称是：当前线程是  [{}] [{}]", serviceId, Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {

        }
        return hystrixService.getNacosClientInfo(serviceId);
    }

    @GetMapping("/getHystrixServiceCommand")
    public List<ServiceInstance> getHystrixServiceCommand(@RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        log.info("服务名称是：当前线程是  [{}] [{}]", serviceId, Thread.currentThread().getName());


        // 第一种方式
        List<ServiceInstance> serviceInstances01 = new HystrixServiceCommand(
                nacosClientService, serviceId
        ).execute();    // 同步阻塞
        log.info("同步阻塞 use execute to get service instances: [{}], [{}]",
                JSON.toJSONString(serviceInstances01), Thread.currentThread().getName());

        // 第二种方式
        List<ServiceInstance> serviceInstances02 = null;
        Future<List<ServiceInstance>> future = new HystrixServiceCommand(
                nacosClientService, serviceId
        ).queue();      // 异步非阻塞
        // 这里可以做一些别的事, 需要的时候再去拿结果
        try {
            serviceInstances02 = future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        log.info("异步非阻塞 use queue to get service instances: [{}], [{}]",
                JSON.toJSONString(serviceInstances02), Thread.currentThread().getName());

        // 第三种方式
        Observable<List<ServiceInstance>> observable = new HystrixServiceCommand(
                nacosClientService, serviceId
        ).observe();        // 热响应调用
        List<ServiceInstance> serviceInstances03 = observable.toBlocking().single();
        log.info("use observe to get service instances: [{}], [{}]",
                JSON.toJSONString(serviceInstances03), Thread.currentThread().getName());

        // 第四种方式
        Observable<List<ServiceInstance>> toObservable = new HystrixServiceCommand(
                nacosClientService, serviceId
        ).toObservable();        // 异步冷响应调用
        List<ServiceInstance> serviceInstances04 = toObservable.toBlocking().single();
        log.info("use toObservable to get service instances: [{}], [{}]",
                JSON.toJSONString(serviceInstances04), Thread.currentThread().getName());

        // execute = queue + get
        return serviceInstances01;
    }

    /**
     * <h3>信号量隔离策率——编码方式实现</h3>
     */
    @GetMapping("/hystrix-observable-command")
    public List<ServiceInstance> getServiceInstancesByServiceIdObservable(
            @RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {

        List<String> serviceIds = Arrays.asList(serviceId, serviceId, serviceId);
        List<List<ServiceInstance>> result = new ArrayList<>(serviceIds.size());

        NacosClientHystrixObservableCommand observableCommand =
                new NacosClientHystrixObservableCommand(nacosClientService, serviceIds);

        // 异步执行命令
        Observable<List<ServiceInstance>> observe = observableCommand.observe();

        // 注册获取结果
        observe.subscribe(
                new Observer<List<ServiceInstance>>() {

                    // 执行 onNext 之后再去执行 onCompleted
                    @Override
                    public void onCompleted() {
                        log.info("all tasks is complete: [{}], [{}]",
                                serviceId, Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onNext(List<ServiceInstance> instances) {
                        result.add(instances);
                    }
                }
        );

        log.info("observable command result is : [{}], [{}]",
                JSON.toJSONString(result), Thread.currentThread().getName());
        return result.get(0);
    }

    /**
     * <h3>编程方式实现请求缓存</h3>
     */
    @GetMapping("/cacheHystrixServiceCommand")
    public void CacheHystrixServiceCommand(
            @RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        CacheHystrixServiceCommand command1 = new CacheHystrixServiceCommand(nacosClientService, serviceId);
        CacheHystrixServiceCommand command2 = new CacheHystrixServiceCommand(nacosClientService, serviceId);
        List<ServiceInstance> result1 = command1.execute();
        List<ServiceInstance> result2 = command2.execute();
        log.info("get cacheHystrixServiceCommand info result1 [{}]  result2 [{}]"
                , JSON.toJSONString(result1), JSON.toJSONString(result2));
        //   清除请求缓存
        CacheHystrixServiceCommand.clearRequestCache(serviceId);
        log.info(">>>>>再次发送请求<<<<<<");
        CacheHystrixServiceCommand command3 = new CacheHystrixServiceCommand(nacosClientService, serviceId);
        CacheHystrixServiceCommand command4 = new CacheHystrixServiceCommand(nacosClientService, serviceId);
        List<ServiceInstance> result3 = command3.execute();
        List<ServiceInstance> result4 = command4.execute();
        log.info("get cacheHystrixServiceCommand info result1 [{}]  result2 [{}]"
                , JSON.toJSONString(result3), JSON.toJSONString(result4));
    }

    @GetMapping("/cacheServiceInstances01")
    public List<ServiceInstance> cacheServiceInstances01(
            @RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        List<ServiceInstance> instances01 = cacheHystrixAnnotationsCommond.cacheServiceInstances01(serviceId);
        List<ServiceInstance> instances02 = cacheHystrixAnnotationsCommond.cacheServiceInstances01(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances01),JSON.toJSONString(instances02));

        //清除缓存
        cacheHystrixAnnotationsCommond.clearRequestCach01(serviceId);

        List<ServiceInstance> instances04 = cacheHystrixAnnotationsCommond.cacheServiceInstances01(serviceId);
        List<ServiceInstance> instances03 = cacheHystrixAnnotationsCommond.cacheServiceInstances01(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances04),JSON.toJSONString(instances03));
        return instances01;
    }

    @GetMapping("/cacheServiceInstances02")
    public List<ServiceInstance> cacheServiceInstances02(
            @RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        List<ServiceInstance> instances01 = cacheHystrixAnnotationsCommond.cacheServiceInstances02(serviceId);
        List<ServiceInstance> instances02 = cacheHystrixAnnotationsCommond.cacheServiceInstances02(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances01),JSON.toJSONString(instances02));

        //清除缓存
        cacheHystrixAnnotationsCommond.clearRequestCach02(serviceId);

        List<ServiceInstance> instances04 = cacheHystrixAnnotationsCommond.cacheServiceInstances02(serviceId);
        List<ServiceInstance> instances03 = cacheHystrixAnnotationsCommond.cacheServiceInstances02(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances04),JSON.toJSONString(instances03));
        return instances01;
    }

    @GetMapping("/cacheServiceInstances03")
    public List<ServiceInstance> cacheServiceInstances03(
            @RequestParam(defaultValue = "e-commerce-nacos-client") String serviceId) {
        List<ServiceInstance> instances01 = cacheHystrixAnnotationsCommond.cacheServiceInstances03(serviceId);
        List<ServiceInstance> instances02 = cacheHystrixAnnotationsCommond.cacheServiceInstances03(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances01),JSON.toJSONString(instances02));

        //清除缓存
        cacheHystrixAnnotationsCommond.clearRequestCach03(serviceId);

        List<ServiceInstance> instances04 = cacheHystrixAnnotationsCommond.cacheServiceInstances03(serviceId);
        List<ServiceInstance> instances03 = cacheHystrixAnnotationsCommond.cacheServiceInstances03(serviceId);
        log.info("get ServiceInstance info : instances01 [{}] and  instances01 [{}]",
                JSON.toJSONString(instances04),JSON.toJSONString(instances03));
        return instances01;
    }

    /**
     * <h2>编程方式实现请求合并</h2>
     * */
    @GetMapping("/request-merge")
    public void requestMerge() throws Exception {

        // 前三个请求会被合并
        NacosClientCollapseCommand collapseCommand01 = new NacosClientCollapseCommand(
                nacosClientService, "e-commerce-nacos-client1");
        NacosClientCollapseCommand collapseCommand02 = new NacosClientCollapseCommand(
                nacosClientService, "e-commerce-nacos-client2");
        NacosClientCollapseCommand collapseCommand03 = new NacosClientCollapseCommand(
                nacosClientService, "e-commerce-nacos-client3");

        Future<List<ServiceInstance>> future01 = collapseCommand01.queue();
        Future<List<ServiceInstance>> future02 = collapseCommand02.queue();
        Future<List<ServiceInstance>> future03 = collapseCommand03.queue();

        future01.get();
        future02.get();
        future03.get();

        Thread.sleep(2000);

        // 过了合并的时间窗口, 第四个请求单独发起
        NacosClientCollapseCommand collapseCommand04 = new NacosClientCollapseCommand(
                nacosClientService, "e-commerce-nacos-client4");
        Future<List<ServiceInstance>> future04 = collapseCommand04.queue();
        future04.get();
    }

    /**
     * <h2>注解的方式实现请求合并</h2>
     * */
    @GetMapping("/request-merge-annotation")
    public void requestMergeAnnotation() throws Exception {

        Future<List<ServiceInstance>> future01 = nacosClientService.findNacosClientInfo(
                "e-commerce-nacos-client1"
        );
        Future<List<ServiceInstance>> future02 = nacosClientService.findNacosClientInfo(
                "e-commerce-nacos-client2"
        );
        Future<List<ServiceInstance>> future03 = nacosClientService.findNacosClientInfo(
                "e-commerce-nacos-client3"
        );

        future01.get();
        future02.get();
        future03.get();

        Thread.sleep(2000);

        Future<List<ServiceInstance>> future04 = nacosClientService.findNacosClientInfo(
                "e-commerce-nacos-client4"
        );
        future04.get();
    }

}